﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bigger.Study.ConsoleApp.Autofac.Reflection_Components
{
    class ReflectionComponentsExample : IExample
    {
        /*
        1、注入默认构造函数和指定构造函数

        public class MyComponent
        {
            public MyComponent() {  }
            public MyComponent(ILogger logger) {  }
            public MyComponent(ILogger logger, IConfigReader reader) {  }
        }


        When you resolve your component, Autofac will see that you have an ILogger registered, but you don’t have an IConfigReader registered. In that case, the second constructor will be chosen since that’s the one with the most parameters that can be found in the container.
        You can manually choose a particular constructor to use and override the automatic choice by registering your component with the UsingConstructor method and a list of types representing the parameter types in the constructor:

        builder.RegisterType<MyComponent>().UsingConstructor(typeof(ILogger), typeof(IConfigReader));


        2、注册实例
        In some cases, you may want to pre-generate an instance of an object and add it to the container for use by registered components. You can do this using the RegisterInstance method:

        var output = new StringWriter();
        builder.RegisterInstance(output).As<TextWriter>();


        Something to consider when you do this is that Autofac automatically handles disposal of registered components and you may want to control the lifetime yourself rather than having Autofac call Dispose on your object for you. In that case, you need to register the instance with the ExternallyOwned method:

        var output = new StringWriter();
        builder.RegisterInstance(output).As<TextWriter>().ExternallyOwned();


        Registering provided instances is also handy when integrating Autofac into an existing application where a singleton instance already exists and needs to be used by components in the container. Rather than tying those components directly to the singleton, it can be registered with the container as an instance:
        
        builder.RegisterInstance(MySingleton.Instance).ExternallyOwned();


        3、Lambda表达式注册
        Autofac can accept a delegate or lambda expression to be used as a component creator:

        builder.Register(c => new A(c.Resolve<B>()));


        Constructor parameters can’t always be declared with simple constant values. Rather than puzzling over how to construct a value of a certain type using an XML configuration syntax, use code:

        builder.Register(c => new UserSession(DateTime.Now.AddMinutes(25)));


        4、Property Injection
        While Autofac offers a more first-class approach to property injection, you can use expressions and property initializers to populate properties as well:

        builder.Register(c => new A(){ MyB = c.ResolveOptional<B>() });

        The ResolveOptional method will try to resolve the value but won’t throw an exception if the service isn’t registered. (You will still get an exception if the service is registered but can’t properly be resolved.) This is one of the options for resolving a service.
        Property injection is not recommended in the majority of cases. Alternatives like the Null Object pattern, overloaded constructors or constructor parameter default values make it possible to create cleaner, “immutable” components with optional dependencies using constructor injection.


        5、Selection of an Implementation by Parameter Value

        builder.Register<CreditCard>(
          (c, p) =>
            {
              var accountId = p.Named<string>("accountId");
              if (accountId.StartsWith("9"))
              {
                return new GoldCard(accountId);
              }
              else
              {
                return new StandardCard(accountId);
              }
            });

        var card = container.Resolve<CreditCard>(new NamedParameter("accountId", "12345"));


        6、Open Generic Components

        Autofac supports open generic types. Use the RegisterGeneric() builder method:

        builder.RegisterGeneric(typeof(NHibernateRepository<>)).As(typeof(IRepository<>)).InstancePerLifetimeScope();


        When a matching service type is requested from the container, Autofac will map this to an equivalent closed version of the implementation type:

        // Autofac will return an NHibernateRepository<Task>
        var tasks = container.Resolve<IRepository<Task>>();


        7、Services vs. Components

        When you register components, you have to tell Autofac which services that component exposes. By default, most registrations will just expose themselves as the type registered:

        // This exposes the service "CallLogger"
        builder.RegisterType<CallLogger>();
        Components can only be resolved by the services they expose. In this simple example it means:

        // This will work because the component
        // exposes the type by default:
        scope.Resolve<CallLogger>();

        // This will NOT work because we didn't
        // tell the registration to also expose
        // the ILogger interface on CallLogger:
        scope.Resolve<ILogger>();
        You can expose a component with any number of services you like:

        builder.RegisterType<CallLogger>()
               .As<ILogger>()
               .As<ICallInterceptor>();
        Once you expose a service, you can resolve the component based on that service. Note, however, that once you expose a component as a specific service, the default service (the component type) is overridden:

        // These will both work because we exposed
        // the appropriate services in the registration:
        scope.Resolve<ILogger>();
        scope.Resolve<ICallInterceptor>();

        // This WON'T WORK anymore because we specified
        // service overrides on the component:
        scope.Resolve<CallLogger>();
        If you want to expose a component as a set of services as well as using the default service, use the AsSelf method:

        builder.RegisterType<CallLogger>()
               .AsSelf()
               .As<ILogger>()
               .As<ICallInterceptor>();
        Now all of these will work:

        // These will all work because we exposed
        // the appropriate services in the registration:
        scope.Resolve<ILogger>();
        scope.Resolve<ICallInterceptor>();
        scope.Resolve<CallLogger>();


        8、Default Registrations

        If more than one component exposes the same service, Autofac will use the last registered component as the default provider of that service:

        builder.Register<ConsoleLogger>().As<ILogger>();
        builder.Register<FileLogger>().As<ILogger>();
        In this scenario, FileLogger will be the default for ILogger because it was the last one registered.

        To override this behavior, use the PreserveExistingDefaults() modifier:

        builder.Register<ConsoleLogger>().As<ILogger>();
        builder.Register<FileLogger>().As<ILogger>().PreserveExistingDefaults();
        In this scenario, ConsoleLogger will be the default for ILogger because the later registration for FileLogger used PreserveExistingDefaults().

        */
        public void Execute()
        {

        }
    }
}
